package com.zf.javassist;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

/**
 * Javassist 工具的使用
 */
public class JavassistMainTest {

    public static void main(String[] args) throws Exception {

        // // 直接调用原始类对象的方法，会加载类
        // Student student = new Student();
        // student.setAge(50);


        // 获取一个默认类池
        ClassPool classPool = ClassPool.getDefault();

        // 获取某个类
        CtClass stuCtClass = classPool.get("com.zf.javassist.Student");
        CtClass integerCtClass = classPool.get("java.lang.Integer");

        // 获取类中的某个方法
        CtMethod getAge = stuCtClass.getDeclaredMethod("setAge", new CtClass[]{integerCtClass});
        // 在方法的开始插入 一段语句
        getAge.insertBefore("System.out.println(\"调用前1\");System.out.println(\"调用前2\");");
        // 在方法的最后且返回之前插入 一段语句
        getAge.insertAfter("System.out.println(\"调用后1\");System.out.println(\"调用后2\");");


        // 将修改后的字节码写入到文件中，指定目录即可，会自动根据包名创建目录, 如 D:\com\zf\javassist\Student.class
        // stuCtClass.writeFile("D:\\");

        // 将修改后的字节码转成 java.lang.Class， 同时也加载到了jvm中，如果类已经被加载了，则会报错：企图重复定义类
        //
        Class<?> stuClass = stuCtClass.toClass();
        // 创建一个修改后的对象
        Object stu = stuClass.getDeclaredConstructor().newInstance();

        // 获取修改后的方法并执行
        stuClass.getDeclaredMethod("setAge", new Class[]{Integer.class}).invoke(stu, 20);

        System.out.println("==================");

        // 直接调用原始类对象的方法，发现已经是修改后的类了
        Student student2 = new Student();
        student2.setAge(30);

    }

}
